package com.zxl.gtion.shiro;

import com.zxl.gtion.shiro.realm.CustomWxRealm;
import com.zxl.gtion.util.ShiroSessionIdGenerator;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Shiro配置类
 */
@Configuration
public class ShiroConfig {

    private final String CACHE_KEY = "shiro:cache:";
    private final String SESSION_KEY = "shiro:session:";

    //Redis配置
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;

    /**
     * 开启Shiro-aop注解支持
     * @Attention 使用代理方式所以需要开启代码支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    /**
     *  开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)
     */
//    @Bean
//    @ConditionalOnMissingBean
//    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
//        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
//        advisorAutoProxyCreator.setProxyTargetClass(true);
//        return advisorAutoProxyCreator;
//    }


    /**
     * Shiro基础配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
        filters.put("authc", new AuthenticationFilter());
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 注意过滤器配置顺序不能颠倒
        // 配置过滤:不会被拦截的链接
        filterChainDefinitionMap.put("/swagger-ui.html","anon");
        filterChainDefinitionMap.put("/doc.html","anon");
        filterChainDefinitionMap.put("/swagger/**","anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**","anon");
        filterChainDefinitionMap.put("/v2/**","anon");

        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/uploads/**", "anon");
        filterChainDefinitionMap.put("/user/wxLogin", "anon");
        filterChainDefinitionMap.put("/user/test", "anon");
        filterChainDefinitionMap.put("/hospital/getHospitals", "anon");
        filterChainDefinitionMap.put("/hospital/insertHospital", "anon");
        filterChainDefinitionMap.put("/hospital/insertHospitalComment", "anon");
        filterChainDefinitionMap.put("/hospital/insertDefaultHospital", "anon");
        filterChainDefinitionMap.put("/hospital/getCommentByHosId", "anon");
        filterChainDefinitionMap.put("/articleInfo/selectInfoById", "anon");
        filterChainDefinitionMap.put("/catalog/homePage", "anon");
        filterChainDefinitionMap.put("/catalog/homeVaccine", "anon");
        filterChainDefinitionMap.put("/catalog/getContentByCatalogId", "anon");
        filterChainDefinitionMap.put("/catalog/moreVaccine", "anon");
        filterChainDefinitionMap.put("/catalog/getArticlePage", "anon");
        filterChainDefinitionMap.put("/catalog/searchVaccine", "anon");
        filterChainDefinitionMap.put("/subject/answerInterface", "anon");
        filterChainDefinitionMap.put("/subject/userAnswer", "anon");
        filterChainDefinitionMap.put("/subject/myPrize", "anon");
        filterChainDefinitionMap.put("/subject/isHavePrize", "anon");
        filterChainDefinitionMap.put("/video/getVideoInfo", "anon");
        filterChainDefinitionMap.put("/banner/video", "anon");
        filterChainDefinitionMap.put("/baidu/ernie4", "anon");
        filterChainDefinitionMap.put("/subject/feeBack", "anon");
        filterChainDefinitionMap.put("/city/cityMap", "anon");
        filterChainDefinitionMap.put("/upload/**", "anon");
        filterChainDefinitionMap.put("/user/unauth", "anon");
        filterChainDefinitionMap.put("/**", "authc");
        // 配置shiro默认登录界面地址，前后端分离中登录界面跳转应由前端路由控制，后台仅返回json数据
        shiroFilterFactoryBean.setLoginUrl("/user/unauth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        shiroFilterFactoryBean.setFilters(filters);

        return shiroFilterFactoryBean;
    }

    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setAuthenticator(modularRealmAuthenticator());
        // 自定义Ssession管理
        securityManager.setSessionManager(sessionManager());
        // 自定义Cache实现
        securityManager.setCacheManager(cacheManager());

        List<Realm> realms = new ArrayList<>();
//        realms.add(webShiroRealm());
        realms.add(customWxRealm());
        securityManager.setRealms(realms);
        return securityManager;
    }



    /**
     * 自定义的Realm管理，主要针对多realm
     */
    @Bean("myModularRealmAuthenticator")
    public MyModularRealmAuthenticator modularRealmAuthenticator() {
        MyModularRealmAuthenticator customizedModularRealmAuthenticator = new MyModularRealmAuthenticator();
        // 设置realm判断条件
        customizedModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return customizedModularRealmAuthenticator;
    }


    /**
     * web端的身份验证器
     */
//    @Bean
//    public WebShiroRealm webShiroRealm() {
//        WebShiroRealm shiroRealm = new WebShiroRealm();
//        shiroRealm.setName(LoginType.USER_WEB_PASSWORD.getType());
//        //自定义的密码验证器
//        shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
//        return shiroRealm;
//    }
    @Bean
    public CustomWxRealm customWxRealm() {
        CustomWxRealm shiroRealm = new CustomWxRealm();
        shiroRealm.setName(LoginType.WECHAT_LOGIN.getType());
        //自定义的密码验证器

        return shiroRealm;
    }

    /**
     * 配置Redis管理器
     * @Attention 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host + ":" + port);
        redisManager.setTimeout(timeout);
        return redisManager;
    }

    /**
     * 配置Cache管理器
     * 用于往Redis存储权限和角色标识
     * @Attention 使用的是shiro-redis开源插件
     */
    @Bean("ehCacheManager")
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setKeyPrefix(CACHE_KEY);
        // 配置缓存的话要求放在session里面的实体类必须有个id标识
        redisCacheManager.setPrincipalIdFieldName("id");
        return redisCacheManager;
    }

    /**
     * 自定义的SessionID生成器
     */
    @Bean
    public ShiroSessionIdGenerator sessionIdGenerator(){
        return new ShiroSessionIdGenerator();
    }

    /**
     * 配置RedisSessionDAO
     * @Attention 使用的是shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        redisSessionDAO.setSessionIdGenerator(sessionIdGenerator());
        redisSessionDAO.setKeyPrefix(SESSION_KEY);
        redisSessionDAO.setExpire(604800);
        return redisSessionDAO;
    }

    /**
     * 配置Session管理器
     */
//    @Bean
//    public SessionManager sessionManager() {
//        //自定义的Session管理器，获取token
//        ShiroSessionManager shiroSessionManager = new ShiroSessionManager();
//        shiroSessionManager.setSessionDAO(redisSessionDAO());
//        return shiroSessionManager;
//    }

    @Bean(name = "sessionManager")
    public ShiroSessionManager sessionManager() {
        ShiroSessionManager manager = new ShiroSessionManager();
        manager.setDeleteInvalidSessions(true);
        manager.setSessionValidationSchedulerEnabled(true);
        manager.setSessionDAO(redisSessionDAO());
        manager.setSessionIdCookieEnabled(false);
        manager.setSessionIdUrlRewritingEnabled(false);
        manager.setGlobalSessionTimeout(604800000L);
        return manager;
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //设置加密方式
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //设置散列的次数
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }
}
